Ext.ns('AIR2.UI');
/***************
 * AIR2 LiveEditor Component
 *
 * A PIN.LiveDataView customized to allow editing row-items.
 *
 * @class AIR2.UI.LiveEditor
 * @extends PIN.LiveDataView
 * @xtype air2liveeditor
 * @cfg {String} url
 *   Restful url for adding/removing tags
 * @cfg {String} sortField
 * @cfg {String} sortDir
 * @cfg {Ext.Template} tpl
 *   Template to render the LiveDataView with. Note that LiveDataViews provide
 *   their own itemSelector... so don't provide one.
 * @cfg {Integer} pageSize
 * @cfg {Boolean} allowEdit
 * @cfg {Boolean} allowDelete
 * @cfg {Boolean} hideButtons
 *   True to hide the default edit/delete buttons. In this case, you should
 *   provide your own edit/delete in the tpl, using the classes 'air2-rowedit'
 *   and 'air2-rowdelete'.
 * @cfg {Object} editForm
 *   Configuration options to pass to an AIR2.UI.FormEditor, which will be
 *   used to edit each row item.
 * @event rowedit(liveeditor, rowEl, record, index)
 * @event rowdelete(liveeditor, rowEl, record, index)
 *
 */
AIR2.UI.LiveEditor = function(config) {
    this.editForm = config.editForm;

    // create store to interact with URL
    var myUrl = (config.url.search(/\.json$/) < 0) ? config.url + '.json' : config.url;
    config.store = new PIN.LiveJsonStore({
        url: myUrl,
        pageSize: config.pageSize,
        remoteSort: true,
        sortInfo: config.sortField ? {
            field: config.sortField,
            direction: config.sortDir || 'DESC'
        } : null,
        autoLoad: false,
        autoSave: false,
        autoDestroy: true,
        restful: true,
        writer: new Ext.data.JsonWriter({
            encode: true,
            writeAllFields: false
        })
    });
    delete config.url; // make sure the dataview doesn't see it

    config.store.on('exception', function(proxy, type, action, opt, resp) {
        var decode = Ext.decode(resp.responseText);
        if (decode) {
            var title = (resp.status == 200) ? 'Slight problem:' : resp.statusText;
            this.showError(title, decode.message);
        }
        else {
            this.showError('FATAL ERROR!', resp.responseText);
        }
        config.store.clearModified();
        config.store.rejectChanges();
        this.reloadDataView();
    }, this);

    // create edit/delete links
    if (config.allowEdit || config.allowDelete) {
        this.addEvents('rowedit');
        this.addEvents('rowdelete');
        if (!config.hideButtons) {
            config.prependStatic = '<div class="row-functions">';
            if (config.allowEdit) config.prependStatic += '<button class="air2-rowedit" ext:qtip="Edit"></button>';
            if (config.allowDelete) config.prependStatic += '<button class="air2-rowdelete" ext:qtip="Delete"></button>';
            config.prependStatic += '</div>';
        }
    }

    // call parent constructor
    AIR2.UI.LiveEditor.superclass.constructor.call(this, config);

    // event handlers
    if (config.allowEdit || config.allowDelete) {
        this.on('click', function(dv, index, node, e) {
            if (e.getTarget('.air2-rowedit')) {
                this.fireEvent('rowedit', this, node, this.getRecord(node), index);
                this.createEditor(this.getRecord(node), node);
            }
            else if (e.getTarget('.air2-rowdelete')) {
                this.fireEvent('rowdelete', this, node, this.getRecord(node), index);
                this.createDeleter(this.getRecord(node), node, e.getTarget('.air2-rowdelete'));
            }
        }, this);
    }
    if (!config.allowEdit) this.addClass('hide-rowedit');
    if (!config.allowDelete) this.addClass('hide-rowdelete');

    if (this.ownerCt) {
        // do the initial window total
        this.store.on('add', function() {
            this.updateTotal();
        }, this, {single:true});

        // watch show/hide events of owner container, and refresh on show
        this.ownerCt.on('hide', function() {
            this.clearDataView();
        }, this);
        this.ownerCt.on('show', function() {
            // if we havent requested anything yet, do it now
            if (!this.pagesLoadedStack.length && !this.pagesRequestedStack.length) {
                this.reloadDataView();
            }
        }, this);

        // watch the addclicked event of the parent container
        this.ownerCt.on('addclicked', function() {
            // clear on the first add
            if (this.store.totalLength == 0) {
                if (this.pageElementMap && this.pageElementMap.length > 0) {
                    this.pageElementMap[0].update('');
                }
            }

            var rec = new this.store.recordType();
            this.store.insert(0, rec);
            this.createEditor(rec, this.getNode(rec));
        }, this);

    }
}
Ext.extend(AIR2.UI.LiveEditor, PIN.LiveDataView, {
    style: 'padding: 0 5px',
    overClass: 'row-over',
    emptyText: '<div class="air2-panel-empty"><h3>(none)</h3></div>',
    listeners: {
        render: function() {this.refreshLoadMask()}
    },
    createEditor: function(record, node) {
        this.editor = new AIR2.UI.FormEditor(this.editForm);
        // only need to listen to cancel, since a save will refresh itself
        this.editor.on('canceledit', function(formpanel, rec) {
            if (!rec.phantom)
                this.refreshNode(this.store.indexOf(rec));
            else if (rec.phantom && this.store.totalLength == 0)
                this.refresh();
        }, this);
        this.editor.on('beforesave', function(formpanel, rec) {
            if (rec.phantom) this.editor.on('aftersave', function() {
                this.store.totalLength += 1;
                this.updateTotal();
            }, this, {single:true});
        }, this);
        this.editor.startEdit(record, node);
    },
    createDeleter: function(rec, node, delEl) {
        var s = rec.store, p = this, n = Ext.get(node), d = Ext.get(delEl);
        if (d.hasClass('selected')) return; // already confirming

        d.addClass('selected');
        var el = d.insertSibling({
            tag: 'span',
            cls: 'delete-confirm air2-corners',
            html: 'Really delete?<br/><a class="yes">Delete</a><a class="no">Cancel</a>'
        }, 'after');
        el.on('click', function(ev) {
            if (ev.getTarget('a.yes')) {
                el.fadeOut({remove:true, callback: function() {
                    n.mask('Deleting');
                    s.remove(rec);
                    if (s.save() < 1) return; //nothing saved
                    s.on('save', function() {
                        n.unmask();
                        s.totalLength -= 1;
                        p.updateTotal();
                        if (s.totalLength == 0) p.refresh();
                    }, this, {single:true});
                }});
            }
            else if (ev.getTarget('a.no')) {
                el.slideOut('l', {duration:.2, remove:true, callback: function() {
                    Ext.fly(delEl).removeClass('selected');
                }});
            }
        }, this);
        el.alignTo(delEl, 'l-r', [8,0]);
        el.slideIn('l', {duration:.2});
    },
    showError: function(title, msg) {
        var el = this.el.insertSibling({
            tag: 'span',
            cls: 'air2-api-error-msg air2-corners',
            html: '<div class="title"><b>'+title+'</b></div>' +
                '<div class="msg"><p>'+msg+'</p></div>' +
                '<div class="btns"></div>'
        });
        var btn = new AIR2.UI.Button({
            air2type: 'DELETE',
            air2size: 'MEDIUM',
            text: 'Okay',
            renderTo: el.child('.btns', false),
            handler: function() {
                el.slideOut('t', {duration:.2, remove:true});
                btn.destroy();
            }
        });
        el.alignTo(this.el, 't-t');
        el.slideIn('t', {duration:.2});

    },
    updateTotal: function() {
        if (this.ownerCt.setTotal) {
            this.ownerCt.setTotal(this.store.getTotalCount());
        }
    }
});
Ext.reg('air2liveeditor', AIR2.UI.LiveEditor);
